use util::RawData;

use super::pointer::*;
use crate::container::{
    ContainerStore,
    ContainerId, ContainerResult, ContainerError
};
use std::sync::Arc;
use crate::rechunk::ReChunk;
use crate::constants::DefaultFingerprintType;

#[derive(RawData,Debug,Clone, Copy)]
pub struct FpPointer {
    id:ContainerId,
    fp:DefaultFingerprintType,
}

impl FpPointer {
    pub fn with_fp(id:ContainerId,fp:&DefaultFingerprintType) -> Self {
        Self {
            id:id,
            fp:*fp,
        }
    }

    pub fn with_zero() -> Self {
        Self {
            id:0,
            fp:DefaultFingerprintType::default(),
        }
    }

    pub fn id(&self) -> ContainerId {
        self.id
    }

    pub fn fp(&self) -> &DefaultFingerprintType {
        &self.fp
    }

    pub fn equal_fp(&self,other:&FpPointer) -> bool {
        self.fp == other.fp
    }
}

impl ChunkPointer for FpPointer {
	//type Index = u32;
	fn new(id:ContainerId,_:u32,fp:&DefaultFingerprintType) -> Self {
        Self {
            id:id,
            fp:*fp,
        }
    }

	fn containerid(&self) -> ContainerId {
        self.id
    }

    fn no(&self) -> u32 {
        0
    }

	fn as_raw_data(&self) -> &[u8] {
        self.as_raw_data()
    }

	fn as_raw_mut(&mut self) -> &mut [u8] {
        self.as_raw_mut()
    }

	fn read(&self,c:&ContainerStore) -> ContainerResult<Arc<ReChunk>> {
        if let Some(chunk) = c.find_chunk_in_read_cache(self.fp()) {
            return Ok(chunk);
        } else {
            return c.read_container(self.id)?
                    .find(self.fp())
                    .map_or(Err(ContainerError::ChunkNotFound), |c|Ok(c));
        }
    }

    fn read_exact(&self,c:&ContainerStore) -> ContainerResult<Arc<ReChunk>> {
        return c.read_container(self.id)?
                .find(self.fp())
                .map_or(Err(ContainerError::ChunkNotFound), |c|Ok(c));
    }
}


#[derive(RawData,Debug)]
pub struct TracePointer {
    id:ContainerId,
    no:u32,
    fp:DefaultFingerprintType,
}

impl TracePointer {
    pub fn no(&self) -> u32 {
        self.no
    }

    pub fn fp(&self) -> &DefaultFingerprintType {
        &self.fp
    }
}

impl ChunkPointer for TracePointer {
	//type Index = u32;
	fn new(id:ContainerId,no:u32,fp:&DefaultFingerprintType) -> Self {
        Self {
            id:id,
            no:no,
            fp:*fp,
        }
    }

	fn containerid(&self) -> ContainerId {
        self.id
    }

    fn no(&self) -> u32 {
        self.no
    }

	fn as_raw_data(&self) -> &[u8] {
        self.as_raw_data()
    }

	fn as_raw_mut(&mut self) -> &mut [u8] {
        self.as_raw_mut()
    }

	fn read(&self,c:&ContainerStore) -> ContainerResult<Arc<ReChunk>> {
        if let Some(chunk) = c.find_chunk_in_read_cache(self.fp()) {
            return Ok(chunk);
        } else {
            return c.read_container(self.id)?
                    .find(self.fp())
                    .map_or(Err(ContainerError::ChunkNotFound), |c|Ok(c));
        }
    }

    fn read_exact(&self,c:&ContainerStore) -> ContainerResult<Arc<ReChunk>> {
        return c.read_container(self.id)?
                .find(self.fp())
                .map_or(Err(ContainerError::ChunkNotFound), |c|Ok(c));
    }
}